﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace Rapattern.Matrix
{
    /// <summary>
    /// 根据汉字从16*16字库文件中查找字模
    /// </summary>
    public class FindMatrixHelper
    {
        private static byte[] GBKMatrixLib;
        private static byte[] GB2312MatrixLib;
        private static string lastErrorMsg = string.Empty;
        /// <summary>
        /// 读取gbk字库文件
        /// </summary>
        /// <param name="fileName">字库文件名</param>
        /// <returns></returns>
        private static bool ReadGBKFile(string fileName= "gbk.dzk")
        {
            bool result = false;
            try
            {
                string path = Environment.CurrentDirectory + "/" + fileName;
                if (!File.Exists(path))
                {
                    lastErrorMsg = "[文件不存在]" + path;
                    result = false;
                    return result;
                }
                FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
                GBKMatrixLib = new byte[fs.Length];
                fs.Read(GBKMatrixLib, 0, GBKMatrixLib.Length);

                result = true;
            }
            catch (Exception ex)
            {
                lastErrorMsg = string.Format("读取文件失败：{0}", fileName) +ex.ToString() ;
                result = false;
            }
            return result;
        }

        /// <summary>
        /// 读取gb2312字库文件
        /// </summary>
        /// <param name="fileName">字库2312文件名</param>
        /// <returns></returns>
        public static bool ReadGB2312File(string fileName = "gbk.dzk")
        {
            bool result = false;
            try
            {
                string path = Environment.CurrentDirectory + "/" + fileName;
                if (!File.Exists(path))
                {
                    lastErrorMsg = "[文件不存在]"+ path;
                    result = false;
                    return result;
                }
                FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
                GB2312MatrixLib = new byte[fs.Length];
                fs.Read(GB2312MatrixLib, 0, GB2312MatrixLib.Length);

                result = true;
            }
            catch (Exception ex)
            {
                lastErrorMsg = string.Format("读取文件失败：{0}", fileName) + ex.ToString();
                result = false;
            }
            return result;
        }

        /// <summary>
        /// 从gbk范围文件中取得字模
        /// </summary>
        /// <param name="name">1个汉字</param>
        /// <param name="msg">错误信息</param>
        /// <param name="defaultValue">设置返回默认值</param>
        /// <returns></returns>
        public static byte[] FindMatrixFromGBK(string name, out string msg, byte[] defaultValue = null)
        {
            msg = null;
            try
            {
                int location = GetLocation(0,name);
                if (location < 0)
                {
                    msg = lastErrorMsg;
                    return defaultValue;
                }

                byte[] matrix = new byte[32];
                Array.Copy(GBKMatrixLib, location, matrix, 0, 32);
                return matrix;
            }
            catch (Exception ex)
            {
                lastErrorMsg = msg = ex.ToString();
                return defaultValue;
            }
        }

        /// <summary>
        /// 从gb2312范围文件中取得字模
        /// </summary>
        /// <param name="name"></param>
        /// <param name="msg"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static byte[] FindMatrixFromGB2312(string name, out string msg, byte[] defaultValue = null)
        {
            msg = null;
            try
            {
                int location = GetLocation(1, name);
                if (location < 0)
                {
                    msg = lastErrorMsg;
                    return defaultValue;
                }

                byte[] matrix = new byte[32];
                Array.Copy(GB2312MatrixLib, location, matrix, 0, 32);
                return matrix;
            }
            catch (Exception ex)
            {
                lastErrorMsg = msg = ex.ToString();
                return defaultValue;
            }
        }

        /// <summary>
        /// 判断文字是否在gbk范围内
        /// </summary>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static bool IsExitFromGBK(string name, bool defaultValue =false)
        {
            try
            {
                int location = GetLocation(0, name);
                if (location < 0)
                {
                    return defaultValue;
                }

                return true;
            }
            catch (Exception ex)
            {
                lastErrorMsg = ex.ToString();
                return defaultValue;
            }
        }

        /// <summary>
        /// 判断文字是否在gb2312中
        /// </summary>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static bool IsExitFromGB2312(string name, bool defaultValue = false)
        {
            try
            {
                int location = GetLocation(1, name);
                if (location < 0)
                {
                    return defaultValue;
                }

                return true;
            }
            catch (Exception ex)
            {
                lastErrorMsg = ex.ToString();
                return defaultValue;
            }
        }

        /// <summary>
        /// 获取最后错误信息
        /// </summary>
        /// <returns></returns>
        public static string GetLastError()
        {
            return lastErrorMsg;
        }

        /// <summary>
        /// 获取文字在字库中的偏移量
        /// </summary>
        /// <param name="flag">0：GBK 1：GB2312</param>
        /// <param name="name">汉字</param>
        /// <returns>-1：错误</returns>
        private static int GetLocation(int flag,string name)
        {
            int location = -1;

            if (flag == 0)
            {
                if (GBKMatrixLib == null)
                {
                    if (!ReadGBKFile())
                    {
                        return -1;
                    }
                }
                byte[] nameArr = Rapattern.Utility.ConvertHelper.StringConvertToBytes(name, "gbk");
                if (nameArr == null || nameArr.Length != 2)
                {
                    lastErrorMsg = string.Format("获取汉字[{0}]GBK编码错误", name);
                    return -1;
                }
                if (nameArr[1] < 0X7F)
                {
                    location = ((nameArr[0] - 0x81) * 190 + nameArr[1] - 0X40) * 32;
                }
                if (nameArr[1] > 0X80)
                {
                    location = ((nameArr[0] - 0x81) * 190 + nameArr[1] - 0X41) * 32;
                }

                if (location < 0 || (location + 32) > GBKMatrixLib.Length)
                {
                    lastErrorMsg = string.Format("[{0}]不在gbk编码范围内");
                    return -1;
                }
            }
            else if (flag == 1)
            {
                if (GB2312MatrixLib == null)
                {
                    if (!ReadGB2312File())
                    {
                        return -1;
                    }
                }
                byte[] nameArr = Rapattern.Utility.ConvertHelper.StringConvertToBytes(name, "gb2312");
                if (nameArr == null || nameArr.Length != 2)
                {
                    lastErrorMsg = string.Format("获取汉字[{0}]GB2312编码错误", name);
                    return -1;
                }

                location = ((nameArr[0] - 0xB0) * 94 + (nameArr[1] - 0xA1)) * 32;

                if (location < 0 || (location + 32) > GB2312MatrixLib.Length)
                {
                    lastErrorMsg = string.Format("[{0}]不在gb2312编码范围内");
                    return -1;
                }
            }
            else
            {
                lastErrorMsg = "未知获取什么编码";
            }

            return location;
        }
    }
}
